package fr.univ.colloque.dao;

import fr.univ.colloque.data.Colloque;
import fr.univ.colloque.data.MotCle;
import fr.univ.colloque.data.Programme;
import fr.univ.colloque.data.vue.ColloqueEvalAbs;
import fr.univ.colloque.util.PoolConnexion;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ColloqueDao
{

    /**
     * Récupère la liste des colloques qui ne sont pas cloturés
     *
     * @param avecMotCle indique si les colloques en retour doivent avoir la
     * liste des mots clés initialisés
     *
     * @return liste de colloques
     */
    public List<Colloque> getLstNonCloture(boolean avecMotCle)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from COLLOQUE where dateFin is null and dateClotureDepot is null";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        List<Colloque> listCo = new ArrayList<Colloque>();

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                int id = rs.getInt("id_colloc");
                String theme = rs.getString("theme");
                String description = rs.getString("description");
                Date dateOuvertureDepot = rs.getDate("dateOuvertureDepot");
                Date dateDebut = rs.getDate("dateDebut");

                MotCleDao mCleDao;
                mCleDao = new MotCleDao();
                List<MotCle> lstMotCle = null;

                if (avecMotCle)
                {
                    lstMotCle = mCleDao.getColloqueMc(id);
                }


                Colloque co = new Colloque(id, theme, description, dateOuvertureDepot, null, dateDebut, null, lstMotCle);

                listCo.add(co);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            // On libère la coonexion du pool de connexion
            pool.fermerConnexion(rs, pStat, con);
        }

        return listCo;
    }

    /**
     * Retourne le colloque correspondant à l'identifiant passé en paramètre
     *
     * @param id identifiant du colloque souhaité
     * @param avecMotCle indique si le colloques en retour doivent avoir la
     * liste des mots clés initialisés
     *
     * @return un colloque ou null si non trouvé
     */
    public Colloque get(int id, boolean avecMotCle)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select * from COLLOQUE where id_colloc=?";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Colloque co = null;

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, id);
            rs = pStat.executeQuery();

            if (rs.next())
            {
                String theme = rs.getString("theme");
                String description = rs.getString("description");
                Date dateOuvertureDepot = rs.getDate("dateOuvertureDepot");
                Date dateDebut = rs.getDate("dateDebut");
                Date dateCloture = rs.getDate("dateClotureDepot");
                Date dateFin = rs.getDate("dateFin");

                MotCleDao mCleDao = new MotCleDao();
                List<MotCle> lstMotCle = null;

                if (avecMotCle)
                {
                    lstMotCle = mCleDao.getColloqueMc(id);
                }

                co = new Colloque(id, theme, description, dateOuvertureDepot, dateCloture, dateDebut, dateFin, lstMotCle);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return co;
    }

    /**
     * Mise à jour des informations du colloque
     *
     * @param co Informations du colloque à mettre à jour
     */
    public void update(Colloque co)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "update COLLOQUE set dateFin=?, dateClotureDepot=?, dateDebut=? where id_colloc=?";

        PreparedStatement pStat = null;

        Connection con = null;

        // Transformation des date de type java.util.Date en java.sql.Date pour permettre la sauvegarde en bdd
        java.sql.Date dtFinSql = null;

        if (co.getDateFin() != null)
        {
            dtFinSql = new java.sql.Date(co.getDateFin().getTime());
        }

        java.sql.Date dtCloture = null;

        if (co.getDateClotureDepot() != null)
        {
            dtCloture = new java.sql.Date(co.getDateClotureDepot().getTime());
        }

        java.sql.Date dtDebut = null;

        if (co.getDateDebut() != null)
        {
            dtDebut = new java.sql.Date(co.getDateDebut().getTime());
        }

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setDate(1, dtFinSql);
            pStat.setDate(2, dtCloture);
            pStat.setDate(3, dtDebut);
            pStat.setInt(4, co.getId());
            pStat.executeUpdate();

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(null, pStat, con);
        }

    }

    /**
     * Sauvegarde un nouveau colloque
     *
     * @param co Nouveau colloque à enregistrer
     *
     * @return l'identifiant généré pour le nouveau colloque enregistré
     */
    public int save(Colloque co)
    {
        String requete = "insert into COLLOQUE (theme, description, dateOuvertureDepot, dateClotureDepot, dateDebut,dateFin) values (?,?,?,?,?,?)";

        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;
        ResultSet rs = null;

        Connection con = null;

        int id = -1;

        // Transformation des date de type java.util.Date en java.sql.Date pour permettre la sauvegarde en bdd
        java.sql.Date dtFin = null;

        if (co.getDateFin() != null)
        {
            dtFin = new java.sql.Date(co.getDateFin().getTime());
        }

        java.sql.Date dtCloture = null;

        if (co.getDateClotureDepot() != null)
        {
            dtCloture = new java.sql.Date(co.getDateClotureDepot().getTime());
        }

        java.sql.Date dtDebut = null;

        if (co.getDateDebut() != null)
        {
            dtDebut = new java.sql.Date(co.getDateDebut().getTime());
        }

        java.sql.Date dtOuvert = null;

        if (co.getDateOuvertureDepot() != null)
        {
            dtOuvert = new java.sql.Date(co.getDateOuvertureDepot().getTime());
        }

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete, Statement.RETURN_GENERATED_KEYS);
            pStat.setString(1, co.getTheme());
            pStat.setString(2, co.getDescription());
            pStat.setDate(3, dtOuvert);
            pStat.setDate(4, dtCloture);
            pStat.setDate(5, dtDebut);
            pStat.setDate(6, dtFin);

            pStat.executeUpdate();

            rs = pStat.getGeneratedKeys();

            if (rs.next())
            {
                id = rs.getInt(1);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return id;
    }

    /**
     * @Todo Fonction non utilisé à voir si on en a besoin qque part !
     * 
     * Récupère le nombre d'exposés pour chaque colloque
     * 
     * @return une Map avec  comme key l'id du colloque et comme valeur le nombre d'exposés
     */
    public Map<Integer, Integer> getNbreExposeParColloque()
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "SELECT e.id_colloc, count( e.id_exp ) FROM EXPOSE GROUP BY e.id_colloc";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Map<Integer, Integer> mColloc = new HashMap<Integer, Integer>();

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                int idColloc = rs.getInt(1);
                int nbExpo = rs.getInt(2);

                mColloc.put(idColloc, nbExpo);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return mColloc;
    }

    /**
     * @Todo Fonction non utilisé à voir si on en a besoin qque part !
     * 
     * Retourne pour chaque id de colloque le nombre d'évaluateur
     *
     * @return une Map avec pour key l'id du colloque et pour valeur le nombre d'évaluateur
     */
    
    public Map<Integer, Integer> getNbreEvalParColloque()
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "SELECT e.id_colloc, count( g.id_pers ) FROM EXPOSE e LEFT JOIN GERER g ON g.id_exp = e.id_exp GROUP BY e.id_colloc";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Map<Integer, Integer> mEval = new HashMap<Integer, Integer>();

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                int idColloc = rs.getInt(1);
                int nbEvaluateur = rs.getInt(2);

                mEval.put(idColloc, nbEvaluateur);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return mEval;
    }

    /**
     * Retourne la liste des comites qui n'ont pas un comité complet avec le
     * nbre d exposé ainsi que le nbre d'eval manquant
     *
     * @return
     */
    public List<ColloqueEvalAbs> getColloqueComiteAbs()
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "SELECT c.*, count(distinct e.id_exp)*2-count(g.id_pers ) 'EvalAbs', count(distinct e.id_exp) 'NbExpo',count(g.id_pers ) FROM COLLOQUE c, EXPOSE e LEFT JOIN GERER g ON g.id_exp = e.id_exp where c.id_colloc=e.id_colloc and c.dateClotureDepot is not null GROUP BY e.id_colloc HAVING count( g.id_pers ) < (SELECT count( e1.id_exp ) *2 FROM EXPOSE e1 WHERE e.id_colloc = e1.id_colloc GROUP BY e1.id_colloc )";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        List<ColloqueEvalAbs> lColloque = new ArrayList<ColloqueEvalAbs>();

        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                int id = rs.getInt("id_colloc");
                String theme = rs.getString("theme");
                String description = rs.getString("description");
                Date dateOuvertureDepot = rs.getDate("dateOuvertureDepot");
                Date dateDebut = rs.getDate("dateDebut");
                Date dateCloture = rs.getDate("dateClotureDepot");
                Date dateFin = rs.getDate("dateFin");
                int nbEvalAbs = rs.getInt("EvalAbs");
                int nbExpo = rs.getInt("NbExpo");


                Colloque co = new Colloque(id, theme, description, dateOuvertureDepot, dateCloture, dateDebut, dateFin, null);
                ColloqueEvalAbs coAbs = new ColloqueEvalAbs(co, nbEvalAbs, nbExpo);

                lColloque.add(coAbs);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }

        return lColloque;
    }

   /**
    * Récupère le nombre de notes manquantes pour un colloque
    * 
    * @param idColloque identifiant du colloque dont on veut connaitre le nombre de notes manquantes
    
    * @return le nombre de notes manquantes
    */    
    public int getNbreNoteAbs(int idColloque)
    {
        PoolConnexion pool = PoolConnexion.getInstance();

        String requete = "select count(*) from GERER where id_exp in ( select e.id_exp from EXPOSE e where id_colloc=?) and (pertinence is null or importance is null or lisibilite is null or decisionFinale is null) ";
        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;

        Colloque co = null;

        int nbre = 0;
        
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            pStat.setInt(1, idColloque);
            rs = pStat.executeQuery();

            if (rs.next())
            {
                nbre = rs.getInt(1);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
        return nbre;
    }
    
    /**
     * Récupère l'ensemble des programmes.
     * 
     * @return 
     */
    public List<Programme> getColloquePourProgramme()
    {
        String requete = "SELECT c.*, count(distinct e.id_exp) 'NbExpo' FROM COLLOQUE c, EXPOSE e LEFT JOIN GERER g ON g.id_exp = e.id_exp where c.id_colloc=e.id_colloc and c.dateFin is null GROUP BY e.id_colloc HAVING count( g.id_pers ) = (SELECT count( e1.id_exp ) *2 FROM EXPOSE e1 WHERE e.id_colloc = e1.id_colloc GROUP BY e1.id_colloc )";
        
        PoolConnexion pool = PoolConnexion.getInstance();

        PreparedStatement pStat = null;

        Connection con = null;
        ResultSet rs = null;
        
        List<Programme> lProg = new ArrayList<Programme>();
       
        try
        {
            con = pool.getConnexion();
            pStat = con.prepareStatement(requete);
            rs = pStat.executeQuery();

            while (rs.next())
            {
                int id = rs.getInt("id_colloc");
                String theme = rs.getString("theme");
                String description = rs.getString("description");
                Date dateOuvertureDepot = rs.getDate("dateOuvertureDepot");
                Date dateDebut = rs.getDate("dateDebut");
                Date dateCloture = rs.getDate("dateClotureDepot");
                Date dateFin = rs.getDate("dateFin");
                int nbExpo = rs.getInt("NbExpo");
                int nbNoteAbs = getNbreNoteAbs(id);

                Colloque co = new Colloque(id, theme, description, dateOuvertureDepot, dateCloture, dateDebut, dateFin, null);
                Programme prog = new Programme(co, nbNoteAbs,nbExpo, null);

                lProg.add(prog);
            }

        }
        catch (SQLException ex)
        {
            Logger.getLogger(PersonneDao.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            pool.fermerConnexion(rs, pStat, con);
        }
        
        return lProg;
    }
}
